#!/usr/bin/python -S
"""Simple logging module.

Simple, as opposed to the crazy Java thing that's in the standard library.  This
also has a focus on logging records.
"""

__author__ = 'Andy Chu'


import sys

import params


EXCEPTION = 50
ERROR = 40
WARNING = 30
INFO = 20  # Default log should be at this level?
PROGRESS = 19  # Terminals should be at this level?  But you don't know if
               # stderr or stdout is a terminal.
DEBUG = 10

_LEVEL_NAMES = {
    # For logging "uncaught" exceptions.  The default logger should send this to
    # a "crash server", if the server location is specified by a flag.
    # Otherwise it could be logged to a special disk file.
    EXCEPTION : 'EXCEPTION',

    # For errors, like not being able to write to a file, or a server.
    ERROR : 'ERROR',

    # For warnings, like skipping bad data?
    WARNING : 'WARNING',

    # For normal information, i.e. I guess a web request should be at this
    # level.
    INFO : 'INFO',

    # For when you're doing something that takes a long time, and you want to
    # show progress?  This should only be shown at the terminal, if a human is
    # watching.  In log files, you don't care how long something takes.
    PROGRESS : 'PROGRESS',

    # For debug tracing.  Not on by default.
    DEBUG : 'DEBUG',

    'EXCEPTION' : EXCEPTION,
    'ERROR' : ERROR,
    'WARNING' : WARNING,
    'INFO' : INFO,
    'PROGRESS' : PROGRESS,
    'DEBUG' : DEBUG,
    }


# Merging params:
#
# Make sure names don't collide -- have an optional prefix
# Shortcut names may collide too

PARAMS = [
    params.OptionalString(
        'verbosity', shortcut='v',
        choices=[p for p in _LEVEL_NAMES.keys() if isinstance(p, str)],
        help='Verbosity level'),
    params.OptionalString(
        'output-stream', shortcut='o', choices=['stderr', 'stdout'],
        help='Stream to log to'),
    ]


class Logger(object):
  """Logs records."""

  def __init__(self, **options):
    #self.options = options
    self.stdout = sys.stdout
    self.stderr = sys.stderr
    self.indent = ''
    # The minimum verbosity level we will show
    self.verbosity = _LEVEL_NAMES['INFO']
    #self.verbosity = _LEVEL_NAMES['DEBUG']

  @classmethod
  def FromParams(cls, params):
    """Construct from a raw parsed params"""
    return cls(**params.ToKeywordArgs(raw_params))

  def debug(self, msg, *args, **kwargs):
    if DEBUG >= self.verbosity:
      self._report(msg, *args, **kwargs)

  def info(self, msg, *args, **kwargs):
    if INFO >= self.verbosity:
      self._report(msg, *args, **kwargs)

  def warning(self, msg, *args, **kwargs):
    if WARNING >= self.verbosity:
      self._report(msg, *args, **kwargs)

  def _report(self, msg, *args, **kwargs):
    if args:
      # HACK for backward compatibility
      self.stderr.write(self.indent + msg % args + '\n')
    else:
      # TODO: Use kwargs
      self.stderr.write(self.indent + msg + '\n')

  def progress(self, msg, *args, **kwargs):
    # No newline, no indent
    self.stderr.write(msg)

  # These control levels of detail
  def push(self):
    self.indent += '  '

  def pop(self):
    self.indent = self.indent[2:]


class NullLogger(object):
  """Can stand in for a logger."""

  def __call__(self, *args, **kwargs):
    return self

  def __getattr__(self, attr):
    return self

NO_LOG = NullLogger()
